package com.zhuhjay.service.system.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.zhuhjay.common.base.exception.BasicBusinessException;
import com.zhuhjay.common.base.util.BeanBuilder;
import com.zhuhjay.common.base.util.JacksonUtils;
import com.zhuhjay.common.redis.util.RedisUtils;
import com.zhuhjay.common.security.context.LoginUserContext;
import com.zhuhjay.common.web.model.vo.PageInfoVo;
import com.zhuhjay.service.system.mapper.SystemNoticeMapper;
import com.zhuhjay.service.system.model.dto.NoticeDto;
import com.zhuhjay.service.system.model.entity.SystemNotice;
import com.zhuhjay.service.system.model.entity.SystemNoticeRead;
import com.zhuhjay.service.system.model.vo.NoticeInfoVo;
import com.zhuhjay.service.system.service.SystemNoticeReadService;
import com.zhuhjay.service.system.service.SystemNoticeService;
import com.zhuhjay.service.system.service.SystemUserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

import static com.zhuhjay.common.base.constant.CacheConstant.NOTICE_DATA_KEY;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Zhuhjay
 * @since 2023-04-13
 */
@Service
public class SystemNoticeServiceImpl extends ServiceImpl<SystemNoticeMapper, SystemNotice> implements SystemNoticeService {

    @Resource
    private SystemNoticeReadService noticeReadService;
    @Resource
    private SystemUserService userService;

    @Override
    public List<NoticeInfoVo> noticesList() {
        Integer userId = LoginUserContext.getUserId();
        // 从redis中获取通知列表
        String data = RedisUtils.getCache(NOTICE_DATA_KEY);
        List<SystemNotice> notices;
        if (StrUtil.isBlank(data)) {
            // 从数据库中获取, 并添加到缓存中(查询的数据是需要状态为1的, 需要过滤)
            notices = this.lambdaQuery().eq(SystemNotice::getStatus, 1)
                    .orderByDesc(SystemNotice::getUpdateTime).list();
            RedisUtils.setCache(NOTICE_DATA_KEY, notices);
            RedisUtils.setKeyExpireMiddle(NOTICE_DATA_KEY);
        } else {
            notices = JacksonUtils.readValue(data, new TypeReference<List<SystemNotice>>() {
            });
        }
        // 获取用户已读的通知id
        List<Integer> readIds = noticeReadService.lambdaQuery().select(SystemNoticeRead::getNoticeId)
                .eq(SystemNoticeRead::getUserId, userId).list()
                .stream().map(SystemNoticeRead::getNoticeId).collect(Collectors.toList());

        return notices.stream()
                .map(notice -> NoticeInfoVo.of2User(notice, readIds.contains(notice.getId())))
                .collect(Collectors.toList());
    }

    @Override
    public PageInfoVo<NoticeInfoVo> noticesPage(Integer pageNum, Integer pageSize) {
        Page<SystemNotice> page = this.lambdaQuery()
                .orderByDesc(SystemNotice::getUpdateTime).page(Page.of(pageNum, pageSize));

        List<NoticeInfoVo> collect = page.getRecords().stream()
                .map(notice -> NoticeInfoVo.of2Admin(notice, userService.getCreateUserByCaffeine(notice.getUserId())))
                .collect(Collectors.toList());

        return BeanBuilder.builder(PageInfoVo<NoticeInfoVo>::new)
                .with(PageInfoVo::setCurrent, page.getCurrent())
                .with(PageInfoVo::setSize, page.getSize())
                .with(PageInfoVo::setTotal, page.getTotal())
                .with(PageInfoVo::setRecords, collect)
                .build();
    }

    @Override
    public void add(NoticeDto notice) {
        this.save(notice.toEntity());
        // 清除缓存
        RedisUtils.deleteCache(NOTICE_DATA_KEY);
    }

    @Override
    public void updateNotice(Integer id, NoticeDto notice) {
        // 判断是否存在
        SystemNotice systemNotice = this.getById(id);
        if (systemNotice == null) {
            throw new BasicBusinessException("不存在该系统通知");
        }
        systemNotice.setTitle(notice.getTitle());
        systemNotice.setContent(notice.getContent());
        this.updateById(systemNotice);
        // 清除缓存
        RedisUtils.deleteCache(NOTICE_DATA_KEY);
    }

    @Override
    public void updateNoticeStatus(Integer id) {
        SystemNotice systemNotice = this.getById(id);
        if (systemNotice == null) {
            throw new BasicBusinessException("不存在该系统通知");
        }
        systemNotice.setStatus(systemNotice.getStatus() == 1 ? 0 : 1);
        this.updateById(systemNotice);
        // 清除缓存
        RedisUtils.deleteCache(NOTICE_DATA_KEY);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteNotice(Integer id) {
        this.removeById(id);
        // 清除缓存
        RedisUtils.deleteCache(NOTICE_DATA_KEY);
        // 删除用户已读记录
        noticeReadService.deleteByNoticeId(id);
    }
}
